
#include "string.h"
#include "ikv_types.h"
#include "optiga_host.h"
#include "ikv_crypto.h"
#include "optiga_curve.h"

static UBYTE rand_pool[32];
void optiga_crypto_rand_init (uint16_t seed)
{
    memset (rand_pool,0,sizeof(rand_pool));
    *(uint16_t*)rand_pool = seed;
    sha256 (rand_pool, rand_pool, sizeof(uint16_t));
    sha256 (rand_pool, rand_pool, sizeof(rand_pool));    
}

void optiga_crypto_rand (UBYTE *rand_str, uint8_t size)
{
    uint8_t c = size, i;
    UBYTE   *ptr = rand_str;
    
    while (c>sizeof(rand_pool)) {
        memcpy (ptr, rand_pool, sizeof(rand_pool));             
        c -= sizeof(rand_pool);
        ptr += sizeof (rand_pool);        
        sha256 (rand_pool, rand_pool, sizeof(rand_pool));
    }

    memcpy (ptr, rand_pool, c);
    if (c>(sizeof(rand_pool)-sizeof(uint16_t))) {
        sha256 (rand_pool, rand_pool, sizeof(rand_pool));
        i = 0;
    } else {
        i = c;
    }
    
    // skip the unused random bytes and use it to generate new random bytes
    sha256 (rand_pool, rand_pool+i, sizeof(rand_pool)-i);
}

void optiga_crypto_gen_lambda (dwordvec_t lambda)
{
	uint8_t i;
	for (i = 0; i < ARRAY_LEN(GF2_163)-1; i++)
        optiga_crypto_rand ((UBYTE*)&lambda[i], sizeof(uint32_t));
	while (i < ARRAY_LEN(MAX_DEGREE)) {
		lambda[i] = 0;
		i++;
    }
}

static dwordvec_t A, B, C, D;
BOOL optiga_crypto_gen_ecc_challenge (dwordvec_t lambda, dwordvec_t ch)
{
	ikv_crypto_ecc_context *ctx;    
	dwordvec_t xA;

		ctx = ecc_init (curve_163);
	if (!ctx)
		return FALSE;

	mont_ecc_mul (ctx, A, B, C, D, ctx->base_point.x_coord, lambda);
		
	if (gf2n_divide (&(ctx->gf2n), xA, A, B))
        return FALSE;
	memcpy ((UBYTE*)ch, (UBYTE*)xA, sizeof(dwordvec_t));
    return TRUE;
}

static UBYTE hash_out[32];
BOOL optiga_crypto_ecdsa_cert_validate (optiga_odc        *cert_ptr, 
							   		    UBYTE             *to_sign,  
									    uint8_t           to_sign_len,
							            issuer_pub_key_t  *issuer_pk)
{
  if(curve_193 == NULL){
    return FALSE;
  }
    sha256 (hash_out, to_sign, to_sign_len);
	return ecdsa_verify (cert_ptr->sig.r_value, cert_ptr->sig.s_value,
					     hash_out, issuer_pk,
					     curve_193);
}	

BOOL optiga_crypto_gen_checkvalue (dwordvec_t lambda, dwordvec_t pubkey, 
                                   dwordvec_t cval)
{
	ikv_crypto_ecc_context *ctx;        

	  	/* initialize finite field and curve parameters */
  	ctx = ecc_init (curve_163);
	
  	/* compute check value */
  	mont_ecc_mul(ctx, A, B, C, D, pubkey, lambda);
  	/* compute affine result */
  	if (gf2n_divide(&(ctx->gf2n), cval, A, B))
        return FALSE;
    else
        return TRUE;
}

BOOL optiga_crypto_gen_session_key (dwordvec_t checkvalue, dwordvec_t z,
                                    dwordvec_t skey)
{
  ikv_crypto_ecc_context *ctx;
  ikv_crypto_ecc_gf2n_context *gf2n;
  
  ctx = ecc_init (curve_163);
  gf2n = &(ctx->gf2n);
 
  /* verify MAC */
  if (dwordvec_iszero (gf2n->degree, z)) {
    return FALSE;
  }
  
  gf2n->mul (skey, checkvalue, z);    
  return TRUE;
}
